<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>表结构文档生成工具</title>
    <script src="/js/vue.js"></script>
    <link rel="icon" type="image/x-icon" href="/icon/favicon.ico">
    <!-- 引入样式 -->
    <link rel="stylesheet" href="/css/element.css">
    <link rel="stylesheet" href="/css/normalize.css">
    <!-- 引入组件库 -->
    <script src="/js/element.js"></script>

    <script src="/js/axios.min.js"></script>

    <link rel="stylesheet" href="/css/document.css">
</head>
<body>
<div id="app">
    <el-container v-loading="loading"
                  element-loading-text="正在加载中..."
                  element-loading-spinner="el-icon-loading"
                  element-loading-background="rgba(0, 0, 0, 0.8)">
        <el-aside width="300px" id="aside">
            <div class="title">表结构文档生成工具</div>
            <el-tree
                    style="margin: 10px"
                    ref="structureTree"
                    :load="loadNode"
                    @check-change="selectNode"
                    lazy
                    show-checkbox
                    node-key="nodeId"
                    :props="defaultProps">
                <template v-slot="{ node, data }">
                    <span>
                        <svg v-if="data.schemaNode" t="1713523736987" class="icon" viewBox="0 0 1024 1024" version="1.1"
                             xmlns="http://www.w3.org/2000/svg" p-id="3270" width="20" height="20"><path
                                d="M522.666667 96l8.533333 0.042667a910.08 910.08 0 0 1 91.562667 5.333333l14.549333 1.706667 15.402667 2.133333 15.125333 2.410667 7.573333 1.322666 14.890667 2.837334c125.205333 25.322667 212.928 79.488 216.256 150.677333l0.106667 4.202667v448c0 73.258667-88.704 129.066667-216.362667 154.88l-14.890667 2.837333-7.573333 1.322667-15.125333 2.389333-15.402667 2.133333c-36.266667 4.650667-74.773333 7.104-114.645333 7.104-39.872 0-78.378667-2.453333-114.645334-7.104l-15.402666-2.133333-15.125334-2.389333c-137.088-23.189333-235.264-79.488-238.72-154.901334L138.666667 714.666667v-448l0.106666-4.202667c3.328-71.189333 91.050667-125.354667 216.256-150.677333l14.890667-2.837334 7.573333-1.322666 15.125334-2.389334 15.402666-2.133333a892.202667 892.202667 0 0 1 97.642667-6.954667L522.666667 96z m145.173333 543.04l-15.125333 2.389333-15.402667 2.133334c-36.266667 4.650667-74.773333 7.104-114.645333 7.104-39.872 0-78.378667-2.453333-114.645334-7.104l-15.402666-2.133334-15.125334-2.389333c-71.488-12.096-132.416-33.194667-174.826666-61.312V714.666667c0 20.949333 24.170667 42.773333 65.066666 61.184l9.749334 4.181333c15.04 6.186667 32 11.925333 50.602666 17.024l12.650667 3.306667c12.864 3.2 26.453333 6.144 40.597333 8.704l14.378667 2.453333 14.741333 2.197333c9.962667 1.386667 20.16 2.602667 30.570667 3.626667l15.765333 1.408 16.064 1.109333 16.362667 0.810667a845.994667 845.994667 0 0 0 66.901333 0l16.362667-0.810667 16.064-1.109333 15.786667-1.408c10.389333-1.024 20.586667-2.24 30.549333-3.626667l14.741333-2.197333 14.378667-2.453333c14.165333-2.56 27.733333-5.482667 40.597333-8.704l12.650667-3.306667c18.602667-5.12 35.562667-10.837333 50.602667-17.024l9.749333-4.181333c39.317333-17.706667 63.189333-38.549333 64.96-58.773334l0.106667-2.410666v-136.96c-42.389333 28.138667-103.317333 49.237333-174.826667 61.333333zM842.666667 364.373333c-40.298667 26.730667-97.28 47.104-164.202667 59.456l-10.666667 1.877334-15.104 2.389333-15.402666 2.133333c-36.266667 4.650667-74.773333 7.104-114.645334 7.104-34.176 0-67.349333-1.792-98.986666-5.248l-15.658667-1.856-15.402667-2.133333-15.125333-2.389333c-71.488-12.096-132.416-33.194667-174.826667-61.312V480c0 20.949333 24.170667 42.773333 65.066667 61.184l9.749333 4.181333c15.04 6.186667 32 11.925333 50.602667 17.024l12.650667 3.306667c12.864 3.2 26.453333 6.144 40.597333 8.704l14.378667 2.453333 14.741333 2.197334c9.962667 1.386667 20.16 2.602667 30.570667 3.626666l15.765333 1.408 16.064 1.109334 16.362667 0.810666a845.994667 845.994667 0 0 0 66.901333 0l16.362667-0.810666 16.064-1.109334 15.786666-1.408c10.389333-1.024 20.586667-2.24 30.549334-3.626666l14.741333-2.197334 14.378667-2.453333c14.165333-2.56 27.733333-5.482667 40.597333-8.704l12.650667-3.306667c18.602667-5.12 35.562667-10.837333 50.602666-17.024l9.749334-4.181333c39.317333-17.706667 63.189333-38.549333 64.96-58.773333l0.106666-2.410667v-115.626667zM522.666667 160l-8.448 0.042667-12.586667 0.213333-12.416 0.405333-16.362667 0.810667-16.064 1.109333-15.786666 1.408c-6.933333 0.682667-13.76 1.450667-20.501334 2.304l-10.026666 1.322667-14.762667 2.197333-14.378667 2.453334c-10.624 1.92-20.906667 4.053333-30.826666 6.336l-9.770667 2.346666-12.650667 3.328c-15.488 4.266667-29.866667 8.96-42.922666 13.973334l-7.68 3.050666-9.749334 4.181334c-40.896 18.410667-65.066667 40.234667-65.066666 61.184 0 20.053333 22.122667 40.874667 59.84 58.773333l5.226666 2.410667 9.749334 4.181333c12.522667 5.162667 26.389333 10.005333 41.450666 14.421333l9.173334 2.602667 12.629333 3.306667c9.642667 2.410667 19.690667 4.650667 30.08 6.72l10.517333 1.984 14.378667 2.453333 14.741333 2.197333c6.634667 0.938667 13.376 1.770667 20.224 2.56l10.346667 1.066667 15.765333 1.408 16.064 1.109333 16.362667 0.810667a845.994667 845.994667 0 0 0 55.872 0.362667l11.029333-0.362667 16.362667-0.810667 16.064-1.109333 15.786667-1.408c6.933333-0.682667 13.76-1.450667 20.501333-2.304l10.026667-1.322667 14.762666-2.197333 14.378667-2.453333c10.624-1.92 20.906667-4.053333 30.826667-6.336l9.770666-2.346667 12.650667-3.328c15.488-4.266667 29.866667-8.96 42.922667-13.973333l7.68-3.050667 9.749333-4.181333c40.896-18.410667 65.066667-40.234667 65.066667-61.184 0-20.053333-22.122667-40.874667-59.84-58.773334l-5.226667-2.410666-9.749333-4.181334a424.469333 424.469333 0 0 0-41.450667-14.421333l-9.173333-2.602667-12.629334-3.306666a623.658667 623.658667 0 0 0-30.08-6.72l-10.517333-1.984-14.378667-2.453334-14.741333-2.197333a765.994667 765.994667 0 0 0-20.224-2.56l-10.346667-1.066667-15.765333-1.408-16.064-1.109333-16.362667-0.810667c-7.317333-0.298667-14.72-0.490667-22.186666-0.597333L522.666667 160z"
                                fill="#409EFF" p-id="iframe3271"></path></svg>
                        <svg v-if="!data.schemaNode" t="1713536034432" class="icon" viewBox="0 0 1024 1024"
                             version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4658"
                             width="20" height="20"><path
                                d="M517.6 188H840c36.8 0 49.6 12.8 49.6 48.8v548.8c0 36.8-12 49.6-48.8 49.6H191.2c-34.4 0-48-12.8-48-47.2V233.6c0-32.8 13.6-45.6 47.2-45.6h327.2zM376.8 662.4H192v124.8h185.6V662.4h-0.8z m232 125.6V663.2H424V788h184.8z m46.4-1.6h185.6v-124H655.2v124zM192 495.2v124h184.8v-124H192zM655.2 620h177.6c3.2 0 8.8-5.6 8.8-8.8 0.8-38.4 0.8-77.6 0.8-116H655.2V620z m-232-1.6h185.6V495.2H423.2v123.2z m-46.4-165.6V328H190.4c0 38.4 0 76 0.8 112.8 0 4 8 11.2 12 11.2 56.8 0.8 114.4 0.8 173.6 0.8z m47.2-2.4h184V328H424v122.4z m416.8 0.8v-124H655.2v124h185.6z"
                                fill="#9AA7B0" p-id="4659"></path></svg>
                    {{ node.label }}
                  </span>
                </template>
            </el-tree>
        </el-aside>
        <el-container id="container">
            <div id="context">
                <el-main>
                    <div class="action-items">
                        <el-button @click="dialogVisible = true" type="text">选择列名</el-button>
                        <el-button @click="preview" type="text">预览文档</el-button>
                        <el-dropdown class="unselectable" @command="download" trigger="click">
                          <span class="el-dropdown-link">下载文档<i
                                  class="el-icon-arrow-down el-icon--right"></i>
                          </span>
                            <el-dropdown-menu slot="dropdown">
                                <el-dropdown-item command="1">Word</el-dropdown-item>
                                <el-dropdown-item command="2">PDF</el-dropdown-item>
                                <el-dropdown-item command="3">Markdown</el-dropdown-item>
                                <el-dropdown-item command="4">HTML</el-dropdown-item>
                            </el-dropdown-menu>
                        </el-dropdown>
                    </div>
                    <iframe id="iframe" :src="pdf"></iframe>
                    <div id="overIframeDiv">
                        <div id="drag-tip"></div>
                    </div>
                </el-main>
            </div>
        </el-container>
    </el-container>
    <el-dialog
            :lock-scroll="false"
            title="选择列名"
            :visible.sync="dialogVisible"
            width="550px">
        <el-checkbox-group v-model="defaultColumns">
            <el-checkbox class="checkbox" :key="item.value" v-for="item of allColumns" :label="item.value">
                {{item.label}}
            </el-checkbox>
        </el-checkbox-group>
        <span slot="footer" class="dialog-footer">
    <el-button size="small" @click="dialogVisible = false">取 消</el-button>
    <el-button size="small" type="primary" @click="dialogVisible = false">确 定</el-button>
  </span>
    </el-dialog>
</div>
<script>
    // 创建一个新的 Vue 实例
    new Vue({
        el: '#app',
        data: {
            data: [],
            loading: false,
            dialogVisible: false,
            allColumns: [],
            defaultColumns: [],
            defaultProps: {
                children: 'children',
                label: 'labelName'
            },
            pdf: ''
        },
        methods: {
            async selectNode(data, selected) {
                let structureTree = this.$refs.structureTree;
                let node = structureTree.getNode(data)
                if (selected && data.childrenCount !== 0 && node.level === 1) {
                    let tables = await this.getTables(data)
                    // 新增子节点
                    structureTree.updateKeyChildren(data.nodeId, tables)
                    this.$nextTick(() => {
                        for (let table of tables) {
                            structureTree.setChecked(table, true)
                            structureTree.getNode(table).isLeaf = true
                        }
                    })
                } else if (!selected && node.level === 2) {
                    structureTree.setChecked(data, false)
                } else if (!selected && node.level === 1 && !structureTree.getHalfCheckedKeys().includes(data.nodeId)) {
                    structureTree.setChecked(data, false)
                    for (let childNode of node.childNodes) {
                        structureTree.setChecked(childNode.data, false)
                    }
                }
            },
            async loadNode(node, resolve) {
                try {
                    this.loading = true;
                    if (node.level === 0) {
                        let databases = await this.getDatabases();
                        resolve(databases);
                        this.$nextTick(() => {
                            let structureTree = this.$refs.structureTree;
                            for (let database of databases) {
                                database.childrenCount === 0 && (structureTree.getNode(database).isLeaf = true)
                            }
                        })
                    } else if (node.level === 1) {
                        let tables = await this.getTables(node.data);
                        resolve(tables);
                        this.$nextTick(() => {
                            let structureTree = this.$refs.structureTree;
                            for (let table of tables) {
                                structureTree.getNode(table).isLeaf = true
                            }
                        })
                    }
                } catch (err) {
                    this.showMessage('error', err)
                    resolve([])
                } finally {
                    this.loading = false;
                }
            },
            getDatabases() {
                return new Promise((resolve, reject) => {
                    axios.get('/document/getDatabases').then(res => {
                        if (res.data.code === 200) {
                            resolve(res.data.data);
                        } else {
                            reject("数据加载失败");
                        }
                    }).catch(err => {
                        reject(err);
                    });
                });
            },
            getTables(data) {
                let schemaName = data.labelName;
                let parentNodeId = data.nodeId;
                return new Promise((resolve, reject) => {
                    axios.get('/document/getTables', {params: {parentNodeId, schemaName}}).then(res => {
                        if (res.data.code === 200) {
                            resolve(res.data.data);
                        } else {
                            reject("数据加载失败");
                        }
                    }).catch(err => {
                        reject(err);
                    });
                });
            },
            getTableColumns() {
                axios.get('/document/getTableColumnInfo').then(res => {
                    if (res.data.code === 200) {
                        this.allColumns = res.data.data.allColumns;
                        this.defaultColumns = res.data.data.defaultColumns;
                    } else {
                        this.showMessage("error", "数据加载失败!")
                    }
                }).catch(err => {
                    this.showMessage("error", "数据加载失败!")
                })
            },
            preview() {
                if (this.getCheckedNodes().length === 0) {
                    this.showMessage("error", "当前未选中任何数据表!")
                    return;
                }
                this.loading = true
                axios({
                    method: 'post',
                    url: '/document/pdf/preview',
                    responseType: 'arraybuffer', // 指定响应类型为二进制流
                    data: {dataList: this.getCheckedNodes(), defaultColumns: this.defaultColumns}
                }).then(res => {
                    if (res.status === 200) {
                        const blob = new Blob([res.data], {type: "application/pdf"});
                        this.pdf = URL.createObjectURL(blob);
                    } else {
                        this.showMessage("error", "预览失败!")
                    }
                    this.loading = false
                }).catch(err => {
                    this.showMessage("error", err.message)
                    this.loading = false
                });
            },
            download(cmd) {
                switch (cmd) {
                    case "1":
                        this.downloadWord();
                        break;
                    case "2":
                        this.downloadPdf();
                        break;
                    case "3":
                        this.downloadMarkdown();
                        break;
                    case "4":
                        this.downloadHtml();
                        break;
                }
            },
            downloadWord() {
                if (this.getCheckedNodes().length === 0) {
                    this.showMessage("error", "当前未选中任何数据表")
                    return;
                }
                this.loading = true
                axios({
                    method: 'post',
                    url: '/document/word/download',
                    responseType: 'blob', // 指定响应类型为二进制流
                    data: {
                        dataList: this.getCheckedNodes(),
                        contentType: this.contentType,
                        defaultColumns: this.defaultColumns
                    }
                }).then(res => {
                    if (res.status === 200) {
                        let blob = new Blob([res.data])
                        let url = window.URL.createObjectURL(blob)
                        let downloadElement = document.createElement('a')
                        downloadElement.style.display = 'none'
                        downloadElement.href = url
                        downloadElement.setAttribute('download', decodeURIComponent(res.headers['filename']))
                        document.body.appendChild(downloadElement)
                        downloadElement.click()
                        document.body.removeChild(downloadElement) // 下载完成移除元素
                        window.URL.revokeObjectURL(url) // 释放掉blob对象
                        this.showMessage("success", "下载成功!")
                    } else {
                        this.showMessage("error", "下载失败!")
                    }
                    this.loading = false
                }).catch(err => {
                    this.showMessage("error", err.message)
                    this.loading = false
                });
            },
            downloadPdf() {
                if (this.getCheckedNodes().length === 0) {
                    this.showMessage("error", "当前未选中任何数据表!")
                    return;
                }
                this.loading = true
                axios({
                    method: 'post',
                    url: '/document/pdf/download',
                    responseType: 'blob', // 指定响应类型为二进制流
                    data: {
                        dataList: this.getCheckedNodes(),
                        contentType: this.contentType,
                        defaultColumns: this.defaultColumns
                    }
                }).then(res => {
                    if (res.status === 200) {
                        let blob = new Blob([res.data])
                        let url = window.URL.createObjectURL(blob)
                        let downloadElement = document.createElement('a')
                        downloadElement.style.display = 'none'
                        downloadElement.href = url
                        downloadElement.setAttribute('download', decodeURIComponent(res.headers['filename']))
                        document.body.appendChild(downloadElement)
                        downloadElement.click()
                        document.body.removeChild(downloadElement) // 下载完成移除元素
                        window.URL.revokeObjectURL(url) // 释放掉blob对象
                        this.showMessage("success", "下载成功!")
                    } else {
                        this.showMessage("error", "下载失败!")
                    }
                    this.loading = false
                }).catch(err => {
                    this.showMessage("error", err.message)
                    this.loading = false
                });
            },
            downloadMarkdown() {
                if (this.getCheckedNodes().length === 0) {
                    this.showMessage("error", "当前未选中任何数据表!")
                    return;
                }
                this.loading = true
                axios({
                    method: 'post',
                    url: '/document/markdown/download',
                    responseType: 'blob', // 指定响应类型为二进制流
                    data: {
                        dataList: this.getCheckedNodes(),
                        contentType: this.contentType,
                        defaultColumns: this.defaultColumns
                    }
                }).then(res => {
                    if (res.status === 200) {
                        let blob = new Blob([res.data])
                        let url = window.URL.createObjectURL(blob)
                        let downloadElement = document.createElement('a')
                        downloadElement.style.display = 'none'
                        downloadElement.href = url
                        downloadElement.setAttribute('download', decodeURIComponent(res.headers['filename']))
                        document.body.appendChild(downloadElement)
                        downloadElement.click()
                        document.body.removeChild(downloadElement) // 下载完成移除元素
                        window.URL.revokeObjectURL(url) // 释放掉blob对象
                        this.showMessage("success", "下载成功!")
                    } else {
                        this.showMessage("error", "下载失败!")
                    }
                    this.loading = false
                }).catch(err => {
                    this.showMessage("error", err.message)
                    this.loading = false
                });
            },
            downloadHtml() {
                if (this.getCheckedNodes().length === 0) {
                    this.showMessage("error", "当前未选中任何数据表!")
                    return;
                }
                this.loading = true
                axios({
                    method: 'post',
                    url: '/document/html/download',
                    responseType: 'blob', // 指定响应类型为二进制流
                    data: {
                        dataList: this.getCheckedNodes(),
                        contentType: this.contentType,
                        defaultColumns: this.defaultColumns
                    }
                }).then(res => {
                    if (res.status === 200) {
                        let blob = new Blob([res.data])
                        let url = window.URL.createObjectURL(blob)
                        let downloadElement = document.createElement('a')
                        downloadElement.style.display = 'none'
                        downloadElement.href = url
                        downloadElement.setAttribute('download', decodeURIComponent(res.headers['filename']))
                        document.body.appendChild(downloadElement)
                        downloadElement.click()
                        document.body.removeChild(downloadElement) // 下载完成移除元素
                        window.URL.revokeObjectURL(url) // 释放掉blob对象
                        this.showMessage("success", "下载成功!")
                    } else {
                        this.showMessage("error", "下载失败!")
                    }
                    this.loading = false
                }).catch(err => {
                    this.showMessage("error", err.message)
                    this.loading = false
                });
            },
            getCheckedNodes() {
                let tree = this.$refs.structureTree;
                let checkedNodes = tree.getCheckedNodes();
                let parentNodeIds = new Set(checkedNodes.filter(node => node.parentNodeId != null).map(node => node.parentNodeId));
                for (let parentNodeId of parentNodeIds) {
                    let node = tree.getNode(parentNodeId).data;
                    if (!checkedNodes.includes(node)) {
                        checkedNodes.push(node)
                    }
                }
                return checkedNodes;
            },
            showMessage(type, message) {
                this.$message({
                    message: message,
                    type: type,
                });
            },
            initChangeBoxWidthEvent() {
                let dragHandle = document.getElementById("drag-tip");
                let startX, startWidth;
                dragHandle.addEventListener("mousedown", function (e) {
                    startX = e.clientX;
                    startWidth = parseInt(document.defaultView.getComputedStyle(document.getElementById("context")).width, 10);
                    document.addEventListener("mousemove", doDrag, false);
                    document.addEventListener("mouseup", stopDrag, false);
                }, false);

                function doDrag(e) {
                    let reduceWidth = e.clientX - startX;
                    let newWidth = startWidth - reduceWidth;
                    if (newWidth > 0) {
                        let container = document.getElementById("context");
                        let aside = document.getElementById("aside");
                        container.style.left = (container.style.left + reduceWidth) + 'px';
                        container.style.width = newWidth + "px";
                        aside.style.width = e.clientX + 'px'
                    }
                }

                function stopDrag() {
                    document.removeEventListener("mousemove", doDrag, false);
                    document.removeEventListener("mouseup", stopDrag, false);
                }
            },
        },
        mounted: function () {
            this.getTableColumns();
            this.initChangeBoxWidthEvent()
        }
    });
</script>
</body>
</html>